package cn.hxsteel.purview.core.tool;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cn.hxsteel.model.bo.ViewBO;
import cn.hxsteel.purview.core.config.constant.ActionConst;
import cn.hxsteel.purview.model.bo.ActionBO;
import cn.hxsteel.purview.model.bo.ModuleBO;
import cn.hxsteel.purview.model.vo.SessionVO;

/**
 * 权限的工具类
 */
public class PurviewTool
{
    /**
     * 动作资源地址的格式
     */
    private final static String          ACTIONURI_FORMAT = "%1$s/%2$s";
    /**
     * 所有的模块业务对象列表的静态变量
     */
    private static List< ModuleBO >      MODULEBO_LIST_ALL;
    /**
     * 所有的权限地图<动作的资源地址,动作标识>的静态变量
     */
    private static Map< String, String > ACTIONURI_AND_ACTIONID_MAP_ALL;
    
    /**
     * 初始化权限数据
     */
    public static void init()
    {
	_getStaticModuleBOListAll();
	System.out.println( "模块初始化完成" );
	_getStaticActionURIAndActionIDMapAll();
	System.out.println( "动作初始化完成" );
    }
    
    /**
     * 获取所有的权限动作标识的键集（系统管理员登录后，就在会话中存放该值。）
     * 
     * @return
     */
    public static Set< String > getPurviewActionIDAll()
    {
	Map< String, String > map = _getStaticActionURIAndActionIDMapAll();
	if ( map == null ) { return null; }
	
	Set< String > res = new HashSet< String >();
	for ( String key : map.keySet() )
	{
	    res.add( map.get( key ) );
	}
	
	return res;
    }
    
    /**
     * 获取当前会话用户的业务视图<键名,动作的资源地址>
     * 
     * @param currentURI 当前请求的资源地址
     * @return
     */
    public static ViewBO getUserActionURIMap( String currentURI, HttpServletRequest request )
    {
	// xml中的所有的模块业务对象的列表
	List< ModuleBO > parentModuleList = _getStaticModuleBOListAll();
	if ( parentModuleList == null ) { return null; }
	
	// uri中的模块资源地址
	currentURI = ( currentURI == null || currentURI.equals( "" ) ) ? request.getRequestURI() : currentURI;
	String moduleURI = _getModuleURI( currentURI );
	if ( moduleURI == null ) { return null; }
	
	// Session中的动作标识的键集
	SessionVO< ? > sessionVO = SessionTool.getSessionVO( request );
	Set< String > sessionActionIDSet = sessionVO.getActionIDSet();
	
	// 收集匹配的动作资源地址的业务视图
	ViewBO res = new ViewBO();
	for ( ModuleBO parentModeulBO : parentModuleList )
	{
	    if ( parentModeulBO.getUri().equals( moduleURI ) )
	    {
		res.put( ActionConst.PARENT_MODULE_ACTION_URI, _getViewActionURI( parentModeulBO ) );
		for ( ModuleBO childPurviewBO : parentModeulBO.getChildModule() )
		{
		    if ( sessionActionIDSet.contains( _getViewActionID( childPurviewBO ) ) )
		    {
			res.put( ActionConst.CHILD_MODULE_ACTION_URI, _getViewActionURI( childPurviewBO ) );
			break;
		    }
		}
		break;
	    }
	    for ( ModuleBO childPurviewBO : parentModeulBO.getChildModule() )
	    {
		if ( childPurviewBO.getUri().equals( moduleURI ) )
		{
		    res.put( ActionConst.CHILD_MODULE_ACTION_URI, _getViewActionURI( childPurviewBO ) );
		    res.put( ActionConst.PARENT_MODULE_ACTION_URI, _getViewActionURI( childPurviewBO.getParentModule() ) );
		    break;
		}
	    }
	}
	return res;
    }
    
    /**
     * 获取当前会话用户的可以访问的上级模块列表
     * 
     * @return
     */
    public static List< ModuleBO > getUserParentModuleBOList( HttpServletRequest request )
    {
	// xml中的所有的模块业务对象的列表
	List< ModuleBO > parentModuleBOList = _getStaticModuleBOListAll();
	if ( parentModuleBOList == null ) { return null; }
	
	// 收集匹配的模块业务对象的列表
	List< ModuleBO > res = new ArrayList< ModuleBO >();
	for ( ModuleBO parentModuleBO : parentModuleBOList )
	{
	    if ( _isOwnModuleViewAction( parentModuleBO, request ) )
	    {
		res.add( parentModuleBO );
	    }
	}
	return res;
    }
    
    /**
     * 获取当前会话用户的可以访问的下级模块列表
     * 
     * @return
     */
    public static List< ModuleBO > getUserChildModuleBOList( HttpServletRequest request )
    {
	// xml中的所有的模块业务对象的列表
	List< ModuleBO > parentModuleBOList = _getStaticModuleBOListAll();
	if ( parentModuleBOList == null ) { return null; }
	
	// uri中当前请求的资源地址
	String currentURI = request.getRequestURI();
	
	// 收集匹配的模块业务对象的列表
	List< ModuleBO > res = new ArrayList< ModuleBO >();
	List< ModuleBO > chilModuleList = new ArrayList< ModuleBO >();
	for ( ModuleBO parentModuleBO : parentModuleBOList )
	{
	    if ( _isActionURIContainsCurrentURI( parentModuleBO, currentURI ) )
	    {
		chilModuleList = parentModuleBO.getChildModule();
		break;
	    }
	    // 因为目前只有二层模块，所以只要获取第一层的下级模块
	    for ( ModuleBO childModuleBO : parentModuleBO.getChildModule() )
	    {
		if ( _isActionURIContainsCurrentURI( childModuleBO, currentURI ) )
		{
		    chilModuleList = childModuleBO.getParentModule().getChildModule();
		    break;
		}
	    }
	}
	for ( ModuleBO childModuleBO : chilModuleList )
	{
	    if ( _isOwnModuleViewAction( childModuleBO, request ) )
	    {
		res.add( childModuleBO );
	    }
	}
	return res;
    }
    
    /**
     * 获取当前会话用户在当前访问模块中可操作的动作名称的键集
     * 
     * @return
     */
    public static Set< String > getUserModuleActionNameSet( HttpServletRequest request )
    {
	// xml中的所有的地图<动作的资源地址,动作标识>
	Map< String, String > actionURIAndActionIDMap = _getStaticActionURIAndActionIDMapAll();
	if ( actionURIAndActionIDMap == null ) { return null; }
	
	// uri中的动作标识
	String currentURI = request.getRequestURI();
	String moduleURI = _getModuleURI( currentURI );
	if ( moduleURI == null ) { return null; }
	
	// Session中的动作标识的键集
	SessionVO< ? > sessionVO = SessionTool.getSessionVO( request );
	Set< String > sessionActionIDSet = sessionVO.getActionIDSet();
	
	// 收集匹配的动作名称的键集
	Set< String > res = new HashSet< String >();
	for ( String key : actionURIAndActionIDMap.keySet() )
	{
	    if ( _getModuleURI( key ).equals( moduleURI ) && sessionActionIDSet.contains( actionURIAndActionIDMap.get( key ) ) )
	    {
		res.add( _getActionName( key ) );
	    }
	}
	
	return res;
    }
    
    /**
     * 获取当前请求的资源地址的动作标识
     * 
     * @param currentURI 当前请求的资源地址
     * @return
     */
    public static String getActionID( String currentURI )
    {
	Map< String, String > map = _getStaticActionURIAndActionIDMapAll();
	if ( map == null ) { return null; }
	
	String currentActionURI = _getStandardActionURI( currentURI );
	if ( !map.containsKey( currentActionURI ) ) { return null; }
	
	return map.get( currentActionURI );
    }
    
    /**
     * 获取指模块查看动作标识
     * 
     * @param moduleBO 模块的业务对象
     * @return
     */
    private static String _getViewActionID( ModuleBO moduleBO )
    {
	if ( moduleBO.getAction().isEmpty() ) { return null; }
	
	String parentModuleID = moduleBO.getParentModule() == null ? "" : moduleBO.getParentModule().getId();
	return parentModuleID + moduleBO.getId() + moduleBO.getAction().get( 0 ).getId();
    }
    
    /**
     * 获取当前请求的资源地址的动作名称
     * 
     * @param currentURI 当前请求的资源地址
     * @return
     */
    private static String _getActionName( String currentURI )
    {
	String currentActionURI = _getStandardActionURI( currentURI );
	if ( currentActionURI == null ) { return null; }
	
	return currentActionURI.substring( currentActionURI.lastIndexOf( "/" ) + 1 );
    }
    
    /**
     * 获取指定模块的查看动作资源地址
     * 
     * @param moduleBO 模块的业务对象
     * @return
     */
    private static String _getViewActionURI( ModuleBO moduleBO )
    {
	if ( moduleBO.getAction().isEmpty() ) { return null; }
	
	return String.format( ACTIONURI_FORMAT, moduleBO.getUri(), moduleBO.getAction().get( 0 ).getName() );
    }
    
    /**
     * 获取当前请求的资源地址的标准动作资源地址
     * 
     * @param currentURI 当前请求的资源地址
     * @return
     */
    private static String _getStandardActionURI( String currentURI )
    {
	String res = null;
	if ( currentURI != null )
	{
	    if ( currentURI.contains( "?" ) )
	    {
		currentURI = currentURI.split( "?" )[0];
	    }
	    if ( currentURI.lastIndexOf( "/do" ) == currentURI.length() - 3 )
	    {
		currentURI = currentURI.substring( 0, currentURI.length() - 3 );
	    }
	    if ( currentURI.lastIndexOf( "/" ) > 0 && currentURI.lastIndexOf( "/" ) < currentURI.length() - 1 )
	    {
		res = currentURI;
	    }
	}
	return res;
    }
    
    /**
     * 获取当前请求的资源地址的模块资源地址
     * 
     * @param currentURI 当前请求的资源地址
     * @return
     */
    private static String _getModuleURI( String currentURI )
    {
	String currentActionURI = _getStandardActionURI( currentURI );
	if ( currentActionURI == null ) { return null; }
	
	return currentActionURI.substring( 0, currentActionURI.lastIndexOf( "/" ) );
    }
    
    /**
     * 指定模块的动作资源地址是否包含当前请求的资源地址
     * 
     * @param moduleBO 模块的业务对象
     * @param currentURI 当前请求的资源地址
     * @return
     */
    private static boolean _isActionURIContainsCurrentURI( ModuleBO moduleBO, String currentURI )
    {
	String currentActionURI = _getStandardActionURI( currentURI );
	if ( currentActionURI == null ) { return false; }
	
	if ( !moduleBO.getAction().isEmpty() )
	{
	    for ( ActionBO actionBO : moduleBO.getAction() )
	    {
		if ( currentActionURI.equals( String.format( ACTIONURI_FORMAT, moduleBO.getUri(), actionBO.getName() ) ) ) { return true; }
	    }
	}
	return false;
    }
    
    /**
     * 当前会话用户是否拥有指定模块的访问权限
     * 
     * @param moduleBO 模块的业务对象
     * @return
     */
    private static boolean _isOwnModuleViewAction( ModuleBO moduleBO, HttpServletRequest request )
    {
	SessionVO< ? > sessionVO = SessionTool.getSessionVO( request );
	Set< String > sessionActionIDSet = sessionVO.getActionIDSet();
	
	String parentModuleID = moduleBO.getParentModule() != null ? moduleBO.getParentModule().getId() : "";
	if ( !moduleBO.getAction().isEmpty() && sessionActionIDSet.contains( parentModuleID + moduleBO.getId() + moduleBO.getAction().get( 0 ).getId() ) ) { return true; }
	
	return false;
    }
    
    /**
     * 获取所有静态的模块业务对象的列表
     * 
     * @return
     */
    private static List< ModuleBO > _getStaticModuleBOListAll()
    {
	if ( MODULEBO_LIST_ALL != null ) { return MODULEBO_LIST_ALL; }
	
	List< ModuleBO > res = null;
	try
	{
	    URL url = Thread.currentThread().getContextClassLoader().getResource( "purview.xml" );
	    File file = new File( url.getPath() );
	    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	    DocumentBuilder builder = factory.newDocumentBuilder();
	    org.w3c.dom.Document doc = builder.parse( file );
	    List< ModuleBO > purviewBOs = new ArrayList< ModuleBO >();
	    NodeList rootNodeList = doc.getElementsByTagName( "purview" );
	    for ( int i = 0; i < rootNodeList.getLength(); i++ )
	    {
		Node rootNode = rootNodeList.item( i );
		if ( rootNode.hasChildNodes() )
		{
		    NodeList parentNodeList = rootNode.getChildNodes();
		    for ( int j = 0; j < parentNodeList.getLength(); j++ )
		    {
			Node parentNode = parentNodeList.item( j );
			NamedNodeMap parentMap = parentNode.getAttributes();
			if ( parentMap != null )
			{
			    // 上级模块
			    ModuleBO parentPurviewBO = new ModuleBO();
			    parentPurviewBO.setId( parentMap.getNamedItem( "id" ).getNodeValue() );
			    parentPurviewBO.setIcon( Short.parseShort( parentMap.getNamedItem( "icon" ).getNodeValue() ) );
			    parentPurviewBO.setName( parentMap.getNamedItem( "name" ).getNodeValue() );
			    parentPurviewBO.setUri( parentMap.getNamedItem( "uri" ).getNodeValue() );
			    parentPurviewBO.setRank( Short.parseShort( parentMap.getNamedItem( "rank" ).getNodeValue() ) );
			    parentPurviewBO.setArray( Short.parseShort( parentMap.getNamedItem( "array" ).getNodeValue() ) );
			    parentPurviewBO.setLockState( Boolean.parseBoolean( parentMap.getNamedItem( "lockState" ).getNodeValue() ) );
			    
			    if ( parentNode.hasChildNodes() )
			    {
				NodeList childNodeList = parentNode.getChildNodes();
				for ( int k = 0; k < childNodeList.getLength(); k++ )
				{
				    Node childNode = childNodeList.item( k );
				    NamedNodeMap childMap = childNode.getAttributes();
				    if ( childMap != null )
				    {
					if ( childNode.hasChildNodes() )
					{
					    // 下级模块
					    ModuleBO childPurviewBO = new ModuleBO();
					    childPurviewBO.setId( childMap.getNamedItem( "id" ).getNodeValue() );
					    childPurviewBO.setIcon( Short.parseShort( childMap.getNamedItem( "icon" ).getNodeValue() ) );
					    childPurviewBO.setName( childMap.getNamedItem( "name" ).getNodeValue() );
					    childPurviewBO.setUri( childMap.getNamedItem( "uri" ).getNodeValue() );
					    childPurviewBO.setRank( Short.parseShort( childMap.getNamedItem( "rank" ).getNodeValue() ) );
					    childPurviewBO.setArray( Short.parseShort( childMap.getNamedItem( "array" ).getNodeValue() ) );
					    childPurviewBO.setLockState( Boolean.parseBoolean( childMap.getNamedItem( "lockState" ).getNodeValue() ) );
					    childPurviewBO.setParentModule( parentPurviewBO );
					    
					    NodeList childChildNodeList = childNode.getChildNodes();
					    for ( int l = 0; l < childChildNodeList.getLength(); l++ )
					    {
						Node childChildNode = childChildNodeList.item( l );
						NamedNodeMap childChildMap = childChildNode.getAttributes();
						if ( childChildMap != null )
						{
						    // 下级模块的动作
						    ActionBO childActionBO = new ActionBO();
						    childActionBO.setId( childChildMap.getNamedItem( "id" ).getNodeValue() );
						    childActionBO.setName( childChildMap.getNamedItem( "name" ).getNodeValue() );
						    childActionBO.setRemark( childChildMap.getNamedItem( "remark" ).getNodeValue() );
						    childActionBO
							    .setLockState( Boolean.parseBoolean( childChildMap.getNamedItem( "lockState" ).getNodeValue() ) );
						    childPurviewBO.getAction().add( childActionBO );
						}
					    }
					    parentPurviewBO.getChildModule().add( childPurviewBO );
					}
					else
					{
					    // 上级模块的动作
					    ActionBO parentActionVO = new ActionBO();
					    parentActionVO.setId( childMap.getNamedItem( "id" ).getNodeValue() );
					    parentActionVO.setName( childMap.getNamedItem( "name" ).getNodeValue() );
					    parentActionVO.setRemark( childMap.getNamedItem( "remark" ).getNodeValue() );
					    parentActionVO.setLockState( Boolean.parseBoolean( childMap.getNamedItem( "lockState" ).getNodeValue() ) );
					    parentPurviewBO.getAction().add( parentActionVO );
					}
				    }
				}
			    }
			    purviewBOs.add( parentPurviewBO );
			}
		    }
		}
	    }
	    res = purviewBOs;
	}
	catch ( Exception e )
	{
	    e.printStackTrace();
	}
	
	MODULEBO_LIST_ALL = res;
	return res;
    }
    
    /**
     * 获取所有静态的地图<动作的资源地址,动作标识>
     * 
     * @return
     */
    private static Map< String, String > _getStaticActionURIAndActionIDMapAll()
    {
	if ( ACTIONURI_AND_ACTIONID_MAP_ALL != null ) { return ACTIONURI_AND_ACTIONID_MAP_ALL; }
	
	List< ModuleBO > parentModuleList = _getStaticModuleBOListAll();
	if ( parentModuleList == null ) { return null; }
	
	Map< String, String > res = new HashMap< String, String >();
	for ( ModuleBO purviewBO : parentModuleList )
	{
	    String parentModuleID = purviewBO.getId();
	    String parentModuleUri = purviewBO.getUri();
	    List< ActionBO > parentActionList = purviewBO.getAction();
	    for ( ActionBO actionBO : parentActionList )
	    {
		String parentActionID = actionBO.getId();
		String parentActionName = actionBO.getName();
		res.put( String.format( ACTIONURI_FORMAT, parentModuleUri, parentActionName ), parentModuleID + parentActionID );
	    }
	    List< ModuleBO > childModuleList = purviewBO.getChildModule();
	    if ( !childModuleList.isEmpty() )
	    {
		for ( ModuleBO purviewBO2 : childModuleList )
		{
		    String childModuleID = purviewBO2.getId();
		    String childModuleUri = purviewBO2.getUri();
		    List< ActionBO > childActionList = purviewBO2.getAction();
		    for ( ActionBO actionVO2 : childActionList )
		    {
			String childActionID = actionVO2.getId();
			String childActionName = actionVO2.getName();
			res.put( String.format( ACTIONURI_FORMAT, childModuleUri, childActionName ), parentModuleID + childModuleID + childActionID );
		    }
		}
	    }
	}
	
	ACTIONURI_AND_ACTIONID_MAP_ALL = res;
	return res;
    }
}